package net.goutalk.glcs.module.workflow.listener;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import net.goutalk.glcs.common.enums.WorkflowNoticePolicyType;
import net.goutalk.glcs.common.enums.YesOrNoEnum;
import net.goutalk.glcs.module.oa.utils.SendMessageUtil;
import net.goutalk.glcs.module.workflow.constant.WorkflowConstant;
import net.goutalk.glcs.module.workflow.entity.WorkflowSchema;
import net.goutalk.glcs.module.workflow.model.MemberConfig;
import net.goutalk.glcs.module.workflow.model.NoticePolicyParam;
import net.goutalk.glcs.module.workflow.model.UserTaskConfig;
import net.goutalk.glcs.module.workflow.model.WorkflowSchemaConfig;
import net.goutalk.glcs.module.workflow.service.IWorkflowSchemaService;
import net.goutalk.glcs.module.workflow.utils.WorkFlowUtil;
import org.camunda.bpm.engine.ProcessEngines;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.task.Task;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 超时提醒 监听器
 * 监听redis key 过期
 *
 * @Author: tanyujie
 * @Date: 2022/10/26 14:46
 */
@Component
public class TaskTimeoutListener extends KeyExpirationEventMessageListener {

    public TaskTimeoutListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String expiredKey = message.toString();

        TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();

        //如果是指定审批人 key 失效
        if (expiredKey.contains(WorkflowConstant.TASK_IS_APPOINT_APPROVE)) {
            String[] split = expiredKey.split(StringPool.UNDERSCORE);
            String taskId = split[0];

            //获取到审批人 发送消息
            Object approvedIds = taskService.getVariableLocal(taskId, WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);

            List<String> variableNames = ListUtil.toList(
                    WorkflowConstant.PROCESS_SCHEMA_ID_KEY,
                    WorkflowConstant.PROCESS_SCHEMA_NAME_KEY,
                    WorkflowConstant.PROCESS_START_USER_NAME_KEY);

            Map<String, Object> variables = taskService.getVariables(taskId, variableNames);

            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

            Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));

            IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
            WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(WorkflowSchema::getJsonContent));

            WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);

            Map<String, Object> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst().orElse(new HashMap<>());
            UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap);


            List<String> approveIds = ListUtil.toList(Convert.toStr(approvedIds).split(StringPool.COMMA));

            NoticePolicyParam param = new NoticePolicyParam();
            param.setNoticeUserIds(Convert.toList(Long.class, approveIds));
            param.setTaskId(task.getId());
            param.setTaskName(task.getName());
            param.setProcessId(task.getProcessInstanceId());
            param.setTaskName(task.getName());
            param.setSchemaId(MapUtil.get(variables, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class));
            param.setSchemaName(MapUtil.get(variables, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, String.class));
            param.setStartUserName(MapUtil.get(variables, WorkflowConstant.PROCESS_START_USER_NAME_KEY, String.class));
            param.setNoticePolicyConfigs(userTaskConfig.getNoticePolicyConfigs());
            //发送消息
            WorkFlowUtil.sendApproveNoticePolicy(param,task.getName());

            //到期未指定的任务 将变量设置为不需要指定
            taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());


            return;
        }

        //如果key 不包含此前缀  不再执行此逻辑
        if (!expiredKey.contains(WorkflowConstant.TIMEOUT_REMID_KEY)) {
            return;
        }


        // 将过期key使用冒号 切割
        String[] expiredKeyArr = expiredKey.split(StringPool.COLON);

        //获取到任务id
        String taskId = expiredKeyArr[1];

        //获取到次数
//        String hit = expiredKeyArr[2];

        //获取到通知策略
        String noticePolicyConfigString = expiredKeyArr[3];
        String[] noticePolicyTypeList = noticePolicyConfigString.split(StringPool.UNDERSCORE);


        //根据taskid  获取发起人 以及 模板名称
        Map<String, Object> variables = taskService.getVariables(taskId, ListUtil.toList(WorkflowConstant.PROCESS_START_USER_NAME_KEY, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY));

        String starter = StrUtil.toString(variables.get(WorkflowConstant.PROCESS_START_USER_NAME_KEY));
        String schemaName = StrUtil.toString(variables.get(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY));

        //获取到需要提醒的人员(过期key  无法获取到value  需要数据库取审批人)
        Object assignee = taskService.getVariableLocal(taskId, WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);

        List<String> approveIds = ListUtil.toList(Convert.toStr(assignee).split(StringPool.COMMA));
        List<Long> ids = Convert.toList(Long.class, approveIds);
        //获取任务信息
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));

        IWorkflowSchemaService workflowSchemaService = SpringUtil.getBean(IWorkflowSchemaService.class);
        WorkflowSchema workflowSchema = workflowSchemaService.getOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(WorkflowSchema::getJsonContent));

        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);

        //找到当前用户任务节点的配置信息
        List<MemberConfig> pushMemberConfigs = workflowSchemaConfig.getProcessConfig().getTimeoutRemidConfig().getPushMemberConfigs();

        if (pushMemberConfigs.size() > 0) {
            List<Long> userIdsByMemberConfig = WorkFlowUtil.getUserIdsByMemberConfig(pushMemberConfigs, workflowSchemaConfig.getChildNodeConfig(), task.getProcessInstanceId());
            ids.addAll(userIdsByMemberConfig);

        }
        List<Long> allPushUserIds = ids.stream().distinct().collect(Collectors.toList());
        //遍历所有设定的通知策略
        // 暂时这样写 后续可以改成 策略模式 或者 工厂模式
        //TODO  sendMessageUtil  改成与 oss 一样的工厂

        NoticePolicyParam param = new NoticePolicyParam();
        param.setNoticeUserIds(Convert.toList(Long.class, allPushUserIds));
        param.setTaskId(task.getId());
        param.setTaskName(task.getName());
        param.setProcessId(task.getProcessInstanceId());
        param.setTaskName(task.getName());
        param.setSchemaId(schemaId);
        param.setSchemaName(schemaName);
        param.setStartUserName(starter);
        for (String type : noticePolicyTypeList) {
            //如果包含系统消息推送
            if (Convert.toInt(type) == WorkflowNoticePolicyType.SYSTEM.getCode()) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutMessage(param);
                });

            }
            //短信发送
            if (Convert.toInt(type) == WorkflowNoticePolicyType.SMS.getCode()) {
                //TODO 短信发送代码
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutSms(param,task.getName());
                });
            }

            //企业微信
            if (Convert.toInt(type) == WorkflowNoticePolicyType.WECHAT.getCode()) {
                //TODO 企业微信发送代码
            }

            //钉钉
            if (Convert.toInt(type) == WorkflowNoticePolicyType.DING.getCode()) {
                //TODO 钉钉发送代码
            }

            //邮箱
            if (Convert.toInt(type) == WorkflowNoticePolicyType.EMAIL.getCode()) {
                //TODO 邮箱发送
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutEmail(param);
                });

            }
        }

    }
}
